package com.lantosec.hmrp.modules.form.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.lantosec.hmrp.core.kit.DownNodeVO;
import com.lantosec.hmrp.core.util.JavaCalculate;
import com.lantosec.hmrp.modules.form.enumeration.ColumnValueTypeEnum;
import com.lantosec.hmrp.modules.form.mapper.FormColumnsMapper;
import com.lantosec.hmrp.modules.form.service.IBindColumnValueService;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.Modifier;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;

import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;

/**
 * 自定义表格列的值绑定计算
 *
 * @author lichaowei
 * @date 2020/4/20
 */
@Service
@Primary
@Log4j2
public class BindColumnValueServiceImpl implements IBindColumnValueService {

    @Autowired
    FormColumnsMapper formColumnsMapper;

    /**
     * 根据值的类型返回相应的值
     *
     */
    @Override
    public Object getBindValue(String valueType, String valueData, JSONObject jsonObject) {

        ColumnValueTypeEnum dataEnum = ColumnValueTypeEnum.getByType(valueType);
        // 替换文本的字段，默认取当前对象的参数，用${field}
        String parameter = com.lantosec.hmrp.core.util.StringUtils.processTemplate(valueData, jsonObject);
        if(!StringUtils.isNotBlank(parameter)){
            return "";
        }
        // 执行对应的方法，获取结果
        Object obj;
        switch (dataEnum) {
            case SQL:
                obj = sqlValue(parameter);
                break;
            case SQL_LIST:
                obj = sqlListValue(parameter);
                break;
            case SQL_MAP_LIST:
                obj = sqlMapListValue(parameter);
                break;
            case DICTIONARIES:
                obj = dictionariesValue(parameter);
                break;
            case JAVASCRIPT_MATH:
                obj = javascriptMathValue(parameter);
                break;
            case JAVA_MATH:
                obj = javaMathValue(parameter);
                break;
            case UPDATE_SQL:
                obj = updateSqlValue(parameter);
                break;
            default:
                obj = defaultValue(parameter);
                break;
        }
        return obj;
    }

    /**
     * 默认值
     */
    private String defaultValue(String parameter) {
        return parameter;
    }

    /**
     * SQL查询值
     */
    private String sqlValue(String parameter) {
        // 根据SQL语句查询一条记录的一个字段，如果有多个返回error，空就返回空字符串
        List<String> list = formColumnsMapper.executeSql(parameter);
        if (CollectionUtils.isEmpty(list)){
            return "";
        }
        else if (list.size() > 1) {
            return "error";
        }
        return list.get(0);
    }

    /**
     * SQL LIST查询列表
     */
    private List<DownNodeVO> sqlListValue(String parameter) {
        return formColumnsMapper.executeListSql(parameter);
    }

    /**
     * SQL MAP LIST查询列表
     */
    private List<Map<String,Object>> sqlMapListValue(String parameter) {
        return formColumnsMapper.executeSelectSql(parameter);
    }

    /**
     * SQL更新
     */
    private int updateSqlValue(String parameter) {
        return formColumnsMapper.executeUpdateSql(parameter);
    }

    /**
     * 字典
     */
    private List<DownNodeVO> dictionariesValue(String parameter) {
        // 根据parent_id查询字典表，返回 key-value list数据
        String sql = "SELECT dictionaries_id 'key', dictionaries_show_name 'value' FROM hmrp.sys_dictionaries WHERE parent_id='" + parameter + "'";
        return formColumnsMapper.executeListSql(sql);
    }

    /**
     * js公式
     */
    private String javascriptMathValue(String parameter) {
        // 执行JS语句，返回结果
        Object result = new Object();
        //引擎管理器
        ScriptEngineManager manager = new ScriptEngineManager();
        //获取引擎
        ScriptEngine engine = manager.getEngineByName("JavaScript");
        try {
            //执行javascript代码
            engine.eval("function mathValue(param){" + parameter + "}");
            //Javascript实现了invocable调用接口
            Invocable inv = (Invocable) engine;
            //调用函数hello,传入world
            result = inv.invokeFunction("mathValue", "param");
        } catch (Exception e) {
            e.printStackTrace();
        }

        return result.toString();
    }

    /**
     * java公式
     */
    private String javaMathValue(String parameter) {
        try {
            // 类库池, jvm中所加载的class
            ClassPool pool = ClassPool.getDefault();
            // 获取指定的类
            CtClass ctClass = pool.get("com.lantosec.hmrp.core.util.JavaCalculate");
            // 创建calc方法, 带两个参数，参数的类型都为int类型
            CtMethod ctMethod = new CtMethod(CtClass.intType, "calculate",
                    new CtClass[]{CtClass.intType, CtClass.intType}, ctClass);
            // 设置方法的访问修饰
            ctMethod.setModifiers(Modifier.PUBLIC);
            // 设置方法体代码
            //ctMethod.setBody("return $1 + $2;");
            ctMethod.setBody(parameter);
            // 添加新建的方法到原有的类中
            ctClass.addMethod(ctMethod);
            // 加载修改后的类
            ctClass.toClass();
            // 创建对象
            JavaCalculate javaCalculate = new JavaCalculate();
            // 获取calc方法
            Method dMethod = JavaCalculate.class.getDeclaredMethod("calculate", new Class[]{int.class, int.class});
            // 反射调用 方法
            Object result = dMethod.invoke(javaCalculate, 10, 20);
            // 打印结果
            System.out.println(String.format("调用calculate方法，传入参数：%d,%d", 10, 20));
            System.out.println("返回结果：" + (int) result);
        }
        catch (Exception ex){
            log.error("JAVA计算错误", ex);
        }
        return null;
    }

}
